// 只组和库修改可见性（设置页面用到）
import React from 'react';
import PropTypes from 'prop-types';
import { Select } from '@teamix/ui';
import { ENUM } from 'utils/constants.js';
import Overlay from './overlay.jsx';
import exceed from 'utils/apimap';
import KEYCODE from 'utils/keycode';
import { getFeature } from 'utils/features';
import './index.scss';
import intl from '../../locale';

const { organization, pathResource } = window.FORCE;

function preventDefault(e) {
  e.preventDefault();
}

const enterpriseSupport = () => {
  if (getFeature('project.setting.basic_setting.publicity')) {
    return [
      {
        value: ENUM.visibility_level.INTERNAL,
        label: intl.get({
          id: 'code-assets.components.accessSelect.setting.VisibleToEnterpriseAccessibleTo',
          defaultMessage: '企业可见(企业内成员可访问)',
        }),
        des: intl.get({
          id: 'code-assets.components.accessSelect.setting.EnterpriseMembersCanAccess',
          defaultMessage: '企业内成员可访问',
        }),
        title: intl.get({
          id: 'code-assets.components.accessSelect.setting.EnterpriseVisible',
          defaultMessage: '企业可见',
        }),
        tip: intl.get({
          id: 'code-assets.components.accessSelect.setting.TheEnterpriseDoesNotSupport',
          defaultMessage: '所属企业不支持该公开性设置，如有需要请联系企业管理员开放',
        }),
      },
    ];
  }
  return [];
};

export default class ProjectModal extends React.Component {
  static propTypes = {
    onChange: PropTypes.func,
    // 组的可见性
    groupAccess: PropTypes.string,
    // 组库标识：是否为库
    isRepo: PropTypes.bool,
    value: PropTypes.number,
  };

  static defaultProps = {
    onChange: () => {},
    groupAccess: '',
    isRepo: true,
    value: 0,
  };

  constructor(props) {
    super(props);
    this.state = {
      isLevelPopVisible: false,
      visibility_level: ENUM.visibility_level.PRIVATE,
      visibility_levels: [
        {
          value: ENUM.visibility_level.PRIVATE,
          label: this.props.isRepo
            ? intl.get({
                id: 'code-assets.components.accessSelect.setting.PrivateVisibleOnlyToMembers',
                defaultMessage: '私有(仅代码库成员可见)',
              })
            : intl.get({
                id: 'code-assets.components.accessSelect.setting.PrivateVisibleOnlyToCode',
                defaultMessage: '私有(仅代码组成员可见)',
              }),
          des: this.props.isRepo
            ? intl.get({
                id: 'code-assets.components.accessSelect.setting.VisibleOnlyToMembersOf',
                defaultMessage: '仅代码库成员可见',
              })
            : intl.get({
                id: 'code-assets.components.accessSelect.setting.VisibleOnlyToCodeGroup',
                defaultMessage: '仅代码组成员可见',
              }),
          title: intl.get({
            id: 'code-assets.components.accessSelect.setting.Private',
            defaultMessage: '私有',
          }),
          tip: intl.get({
            id: 'code-assets.components.accessSelect.setting.TheEnterpriseDoesNotSupport',
            defaultMessage: '所属企业不支持该公开性设置，如有需要请联系企业管理员开放',
          }),
        },
        ...enterpriseSupport(),
        // {
        //   value: ENUM.visibility_level.PUBLIC,
        //   label: '公开(仅代码库成员可见)',
        //   des: '所有登录用户均可访问',
        //   title: '公开',
        //   tip: '受所属组公开性影响，无法选择',
        // },
      ],
      display_levels: [],
      admin_access_visibility_level: [],
      hideTips: [],
      cur_visibility_levels: [],
      // 是否正在请求
      isLoadingSetting: true,
      isLoadingVisibility: true,
      highlightKey: null,
    };
  }

  componentDidMount() {
    this.setState({
      isLoadingSetting: true,
      isLoadingVisibility: true,
    });

    this.getSettingLevels();
  }

  getSettingLevels() {
    // 获取公开性的设置信息
    const { value, isRepo } = this.props;
    exceed
      .forceFetch({
        api: `${isRepo ? 'project' : 'groups'}.setting.visibility`,
        params: {
          id: pathResource.id,
        },
      })
      .then((result) => {
        const { visibility_levels } = this.state;
        const hideTips = [];
        visibility_levels.forEach((item) => {
          const setting = result[item.value];
          // setting.state:enable/disable/hide  可用 禁用 隐藏
          item.iShow = setting.state !== 'hide';
          item.disabled = setting.state === 'disable';
          item.tip = setting.message;
          if (setting.state === 'hide') {
            hideTips.push(setting.message);
          }
        });
        const cur_visibility_levels = visibility_levels.filter((item) => item.iShow);
        this.setState({
          cur_visibility_levels,
          hideTips,
          isLoadingVisibility: false,
        });
      });

    exceed
      .forceFetch({
        api: `organization.${isRepo ? 'repo' : 'group'}.setting.get`,
        params: {
          org_id: organization.id,
        },
      })
      .then((result) => {
        this.setState({
          admin_access_visibility_level: `${
            (isRepo
              ? result.repo_admin_access_visibility_level
              : result.group_admin_access_visibility) || []
          }`,
          display_levels: `${
            (isRepo ? result.repo_display_level : result.group_display_level) || []
          }`,
          visibility_level: Number(value),
          isLoadingSetting: false,
        });
      });
  }

  handleSelect = (item) => {
    this.setState({
      isLevelPopVisible: false,
      visibility_level: item.value,
    });

    this.props.onChange(item.value);
  };

  onVisibleChange = (visible) => {
    this.setState({
      isLevelPopVisible: visible,
      highlightKey: null,
    });
  };

  getLevels = () => {
    const { role = '' } = pathResource;
    const { admin_access_visibility_level, display_levels } = this.state;
    // 企业管理员根据display_level显示，否则还受admin_access_visibility_level限制
    const showLevels = this.state.visibility_levels.filter((item) => {
      return display_levels.indexOf(item.value) > -1;
    });

    const curLevels = showLevels.map((item) => {
      if (['ORG_ADMIN', 'ORG_OWNER', 'ADMIN'].includes(role)) {
        item.disabled = false;
      } else {
        item.disabled = admin_access_visibility_level.indexOf(item.value) === -1;
      }
      return item;
    });

    return curLevels;
  };

  handleKeyDown = (e) => {
    const { isLevelPopVisible, cur_visibility_levels, highlightKey } = this.state;
    switch (e.keyCode) {
      case KEYCODE.UP:
        e.preventDefault();
        this.toggleHighlightItem(-1, e);
        break;
      case KEYCODE.DOWN:
        e.preventDefault();
        this.toggleHighlightItem(1, e);
        break;
      case KEYCODE.ENTER:
        e.preventDefault();
        if (isLevelPopVisible) {
          const highlightItem = cur_visibility_levels.find((item) => item.value === highlightKey);
          highlightItem && this.handleSelect(highlightItem);
        } else {
          this.setState({
            isLevelPopVisible: true,
          });
        }
        break;
      case KEYCODE.ESC:
        e.preventDefault();
        this.setState({
          isLevelPopVisible: false,
        });

        break;
      default:
        break;
    }
  };

  toggleHighlightItem = (dir) => {
    const { cur_visibility_levels } = this.state;
    if (!this.state.isLevelPopVisible) {
      this.setState({
        isLevelPopVisible: true,
      });

      return;
    }

    const enabledData = cur_visibility_levels.filter((item) => !item.disabled);
    const maxCount = enabledData.length;
    // When there is no enabled item
    if (!maxCount) {
      return false;
    }

    let { highlightKey } = this.state;
    let highlightIndex = -1;

    // find previous highlight index
    highlightKey !== null &&
      enabledData.some((item, index) => {
        if (item.value === highlightKey) {
          highlightIndex = index;
        }
        return highlightIndex > -1;
      });

    // toggle highlight index
    highlightIndex += dir;
    if (highlightIndex < 0) {
      highlightIndex = maxCount - 1;
    }
    if (highlightIndex >= maxCount) {
      highlightIndex = 0;
    }

    // get highlight key
    const highlightItem = enabledData[highlightIndex];
    highlightKey = highlightItem ? highlightItem.value : null;

    this.setState({
      highlightKey,
    });
  };

  render() {
    const { isLoadingSetting, isLoadingVisibility, cur_visibility_levels, hideTips, highlightKey } =
      this.state;
    const isLoading = isLoadingSetting && isLoadingVisibility;

    const visibilityPopupContent = (
      <Overlay
        onChange={this.handleSelect}
        onMouseDown={preventDefault}
        selectValue={this.props.value || this.state.visibility_level}
        data={cur_visibility_levels}
        isOverlayLoading={isLoading}
        // 高亮value
        highlightKey={highlightKey}
      />
    );

    const popupProps = {
      triggerClickKeycode: [13, 32], // space, enter
    };

    return (
      <React.Fragment>
        <Select
          {...this.props}
          visible={this.state.isLevelPopVisible}
          onVisibleChange={this.onVisibleChange}
          value={isLoading ? '' : this.props.value || this.state.visibility_level}
          popupProps={popupProps}
          popupContent={visibilityPopupContent}
          dataSource={isLoading ? [] : cur_visibility_levels}
          followTrigger
          onKeyDown={this.handleKeyDown}
        />

        {hideTips.length > 0 &&
          hideTips.map((item) => {
            return <div className="setting-select-tip">{item}</div>;
          })}
      </React.Fragment>
    );
  }
}
